using System;
using System.Net;
using System.Threading;
using System.Xml;
using System.Web.Services.Protocols;
using NUnit.Framework;
using soapclient;

[TestFixture]
public class SOAPHandler {
    void TestWSSuccess(Suds s) {
        s.compute(1);
    }

    void TestWSFailure(Suds s) {
        try {
            s.compute(0);
            Assert.Fail("failed to raise the expected SOAPException");
        }
        catch (SoapException expected) {
            XmlNode detail = expected.Detail;
            Assert.IsNotNull(detail, "No detail: is the web service configured with the correct seanfoy.oopsnet.frameworkSuppliesSoapFaultDetail value?");
            Assert.IsNotNull(detail.OuterXml);
            Assert.AreNotEqual(String.Empty, detail.OuterXml);
            Exception unpacked =
                UnpackClosure.unpack(detail);
            Assert.IsNotNull(unpacked);
            Assert.IsTrue(unpacked is ArgumentException);
        }
    }

    void TestDeepFailure(Suds s) {
        try {
            s.compute(42);
        }
        catch (SoapException e) {
            Assert.IsNotNull(e.Detail, "No detail: is the web service configured with the correct seanfoy.oopsnet.frameworkSuppliesSoapFaultDetail value?");
            
            Exception unpacked =
                UnpackClosure.unpack(e.Detail);
            Assert.IsNotNull(unpacked.InnerException);
        }
    }

    class UnpackClosure {
        public XmlNode input;
        public UnpackClosure(XmlNode input) {
            this.input = input;
        }
        public Exception result;
        public void threadstart() {
            result =
                seanfoy.oopsnet.SOAPErrorHandler.dexmlize(input);
        }
        public static Exception unpack(XmlNode detail) {
            UnpackClosure closure = new UnpackClosure(detail);
            Thread t = null;
            try {
                t = new Thread(new ThreadStart(closure.threadstart));
                t.Start();
                if (!t.Join(TimeSpan.FromSeconds(2))) {
                    Assert.Fail("Timed out unpacking SOAP fault detail. Is the soap demo service misconfigured?");
                }
            }
            catch {
                if (t != null) {
                    try {
                        t.Abort();
                    }
                    catch {
                        //give up on the thread,
                        //deal with the other
                        //problem
                    }
                }
                throw;
            }
            return closure.result;
        }
    }

    [Test]
    public void WSSuccess() {
        WithSuds(new TestDelegate(TestWSSuccess));
    }
    [Test]
    public void WSFailure() {
        WithSuds(new TestDelegate(TestWSFailure));
    }
    [Test]
    public void DeepFailure() {
        WithSuds(new TestDelegate(TestDeepFailure));
    }

    delegate void TestDelegate(Suds s);
    void WithSuds(TestDelegate test) {
        try {
            using (Suds s = new Suds()) {
                test(s);
            }
        }
        catch (WebException e) {
            if (e.Status != WebExceptionStatus.ConnectFailure &&
                e.Status != WebExceptionStatus.ProtocolError) throw;
            Assert.Ignore(e.Message + " You must configure your web server to run the oopsnet SOAP demo for this test to proceed.");
        }
    }
}
